package com.flyfinger.rpcserver.lagou.handler;

import com.flyfinger.pojo.RpcRequest;
import com.flyfinger.pojo.ServiceLocation;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.curator.framework.CuratorFramework;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Random;

/**
 * 自定义的业务处理器
 */
@Component
@ChannelHandler.Sharable
public class UserServiceHandler extends ChannelInboundHandlerAdapter implements BeanFactoryAware {

	private BeanFactory beanFactory;

	private CuratorFramework client;

	static final Random random = new Random();

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		final RpcRequest rpcRequest;
		if (!(msg instanceof RpcRequest)) {
			System.out.println("未获取到RpcRequest");
			return;
		}
		rpcRequest = (RpcRequest) msg;
		System.out.println(String.format("服务端[%s]获取到RpcRequest：[%s]", getPort(), rpcRequest));

		final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		final Class<?> aClass = classLoader.loadClass(rpcRequest.getClassName());
		final Object bean = beanFactory.getBean(aClass);

		final Method method = aClass.getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());
		final Object invoke = method.invoke(bean, rpcRequest.getParameters());

		rpcRequest.setResult(String.format("来自[%s]机器的消息反馈:[%s]", getPort(), invoke));
		System.out.printf("返回值[%s]", rpcRequest);


		final ServiceLocation location = new ServiceLocation("127.0.0.1", port);
		/**
		 假设业务中，服务端已经向客户端发送响应
		 响应客户端和往zookeeper中写入响应时间，是同时进行的
		 假设响应客户端的时候，网络延迟花费了4秒以内的随机时间
		 所以客户端接收到服务端消息的时间，要比服务端实际响应的时间长
		 */
		location.setReplyTime(System.currentTimeMillis() - (random.nextInt(4) * 1000));
		getClient().setData().forPath(getPath(), location.writeAsBytes());


		ctx.writeAndFlush(rpcRequest);
		ctx.close();
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}

	public BeanFactory getBeanFactory() {
		return beanFactory;
	}

	private int port;
	private String path;

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public CuratorFramework getClient() {
		return client;
	}

	public void setClient(CuratorFramework client) {
		this.client = client;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}
}
